<!DOCTYPE html>
<html lang="en">

<head>
  <meta charset="UTF-8">
  <meta http-equiv="X-UA-Compatible" content="IE=edge">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <title>Document</title>
</head>

<body>
  <div>
    <h2>一、构造函数</h2>
    <div>构造函数和普通函数本质上没什么区别，构造函数的首字母一般是大写，用以区分普通函数</div>
    <br>
    <h2>二、原型</h2>
    <div>Person.prototype(在js中，每一个函数类型的数据，都有一个叫做prototype的属性，这个属性指向的是一个对象，就是所谓的原型对象。)</div>
    <h4>1. 显示原型</h4>
    <div>显示原型就是利用prototype属性查找原型，只是这个是函数类型数据的属性</div>
    <h4>2. 隐式原型</h4>
    <div>隐式原型是利用__proto__属性查找原型，可以在实例对象上面使用：</div>
    <br>
    <div>Person.prototype.constructor（对于原型对象来说，它有个constructor属性，指向它的构造函数。）</div>
    <h2>三、原型的作用</h2>
    <div>最主要的作用就是用来存放实例对象的公有属性和公有方法</div>
    <br>
    <div>Function() { [native code] }</div>
    <br>
    <div>JS 语言中自带的原生方法 String、Number、Array、Boolean、Function、Object、Date 等，都是 Function 的实例化对象</div>
      <br>
    <div>Number、Array、Boolean、Function、Object、Date 等 的 constructor 都指向 Function
      （Function 的构造函数也指向 Function，不要疑惑，虽然毫无道理，但是就是这么发生了）</div>

    <h2>四、原型链</h2>
    <div>整个查找过程都是顺着__proto__属性，一步一步往上查找，形成了像链条一样的结构，这个结构，就是原型链。所以，原型链也叫作隐式原型链。</div>
    <br>
    <div>正是因为这个原因，我们在创建(constructor)对象、数组、函数等等数据的时候，都自带一些属性和方法，这些属性和方法是在它们的原型上面保存着，所以它们自创建起就可以直接使用那些属性和方法</div>
    <h2>五、函数也是一种对象</h2>
    <div>函数在js中，也算是一种特殊的对象</div>
  </div>
  <script>
    function Person(name, age) {
      this.name = name;
      this.age = age;
      this.species = '人类';
      this.say = function () {
        console.log("Hello");
      }
    }
    let per1 = new Person('xiaoming', 20);
    console.log(per1);
    console.log(Person.constructor,'Person.constructor');
    console.log(Person.prototype,'Person.prototype原型对象（显示原型）');
    console.log(Person.prototype.constructor,'Person.prototype.constructor构造函数');

    // 在上面那个例子里species属性和say方法对于所有实例来说都一样，放在构造函数里，那每创建一个实例，就会重复创建一次相同的属性和方法，显得有些浪费。这时候，如果把这些公有的属性和方法放在原型对象里共享，就会好很多。
    function Person(name, age) {
    this.name = name;
    this.age = age;
    }
    Person.prototype.species = '人类';
    Person.prototype.say = function () {
        console.log("Hello");
    }
    let pera = new Person('xiaoming', 20);
    let perb = new Person('xiaohong', 19);
    console.log(pera.species); // 人类 
    console.log(perb.species); // 人类
    pera.say(); // Hello
    perb.say(); // Hello

    console.log(perb,'new Person()实例');
    console.log(perb.constructor,'perb.constructor构造函数'); // Person()
    console.log(pera.__proto__,'隐式原型');
    console.log(Person.prototype.__proto__,'Person.prototype.__proto__');
    console.log(Person.prototype.__proto__.__proto__,'Person.prototype.__proto__.__proto__');
    console.log(Person.prototype.__proto__.constructor,'Person.prototype.__proto__.constructor');

    console.log(Person.__proto__,'Person.__proto__');
    console.log(Person.__proto__.__proto__,'Person.__proto__.__proto__');
    console.log(Person.__proto__.__proto__.constructor,'Person.__proto__.__proto__.constructor');
  </script>

  <div>
    <h2>六、总结</h2>
    <div>__proto__作为不同对象之间的桥梁，用来指向创建它的构造函数的原型对象的</div>
    <ul>
      <li>每个对象的__proto__都是指向它的构造函数的原型对象prototype的 person1.__proto__ === Person.prototype</li>
      <li>构造函数是一个函数对象，是通过 Function构造器产生的 Person.__proto__ === Function.prototype</li>
      <li>原型对象本身是一个普通对象，而普通对象的构造函数都是Object Person.prototype.__proto__ === Object.prototype</li>
      <li>所有的构造器都是函数对象，函数对象都是 Function构造产生的 Object.__proto__ === Function.prototype</li>
      <li>Object的原型对象也有__proto__属性指向null，null是原型链的顶端 Object.prototype.__proto__ === null</li>
    </ul>
    <br>
    <div>1.一切对象都是继承自Object对象，Object 对象直接继承根源对象null</div>
    <div>2.一切的函数对象（包括 Object 对象），都是继承自 Function 对象</div>
    <div>3.Object 对象直接继承自 Function 对象</div>
    <div>4.Function对象的__proto__会指向自己的原型对象，最终还是继承自Object对象</div>
  </div>
</body>

</html>